package com.hejia.alauda.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hejia.alauda.entity.*;
import com.hejia.alauda.entity.example.*;
import com.hejia.alauda.persistence.mybatis.*;
import com.hejia.alauda.utils.DateTimeUtil;
import com.hejia.alauda.utils.Pager;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.ObjectId;
import org.joda.time.DateTime;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap;

import javax.annotation.Resource;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.hejia.alauda.event.EventConstant.MONGODB_KEY_HANDLED_FINANCING_IDS;
import static com.hejia.alauda.utils.DateTimeUtil.getMinDate;
import static com.hejia.alauda.utils.Utils.MYSQL_DATE_FORMAT;
import static com.hejia.alauda.utils.Utils.formatDate;
import static java.util.Calendar.getInstance;
import static org.apache.commons.lang3.time.DateFormatUtils.ISO_DATE_FORMAT;
import static org.apache.commons.lang3.time.DateUtils.addDays;
import static org.springframework.util.CollectionUtils.isEmpty;
import static org.apache.commons.collections4.MapUtils.*;
import static com.hejia.alauda.utils.RateUtil.*;
/**
 * Created by Johnny(johnny@hejiajinrong.com) on 15/3/2.
 */

@Service
public class BalanceAndFinancingServiceImpl implements
		BalanceAndFinancingService {
	
	protected final static Log logger = LogFactory.getLog(BalanceAndFinancingServiceImpl.class);
	
	@SuppressWarnings("rawtypes")
	@Resource
	private RedisTemplate redisTemplate;

	@Resource
	private FinancialAssetMapper financialAssetMapper;

	@Resource
	private ProductMapper productMapper;

	@Resource
	private FinancialAssetStockEntryMapper financialAssetStockEntryMapper;

	@Resource
	private FinancingMapper financingMapper;

	@Resource
	private InterestMapper interestMapper;

	@Resource
	private CommonService commonService;
	
	@Resource
	private RedemptionRequestMapper redemptionRequestMapper;
	
	@Resource
	private FinancingIncomeRuleMapper financingIncomeRuleMapper;
	
	@Resource
	private ConfigureService configureService;
	
	@Resource
	private InvitationMapper invitationMapper;
	
	@Override
	public Pager<FinancialAsset> findFinancialAssets(String keyword,
			Date valueDateStart, Date valueDateEnd, Date dueDateStart,
			Date dueDateEnd, Pager<FinancialAsset> pager) {

		DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		FinancialAssetExample example = new FinancialAssetExample();
		if (StringUtils.isNotBlank(keyword)) {
			example.appendCriterion("name like", "%" + keyword + "%");
		}
		if (valueDateStart != null) {
			example.appendCriterion("valueDate >=",
					format.format(valueDateStart));
		}
		if (valueDateEnd != null) {
			example.appendCriterion("valueDate <=", format.format(valueDateEnd));
		}
		if (dueDateStart != null) {
			example.appendCriterion("dueDate >=", format.format(dueDateStart));
		}
		if (dueDateEnd != null) {
			example.appendCriterion("dueDate <=", format.format(dueDateEnd));
		}
		example.setOrderByClause("createDate desc");

		pager.setList(financialAssetMapper.selectByExample(example, pager));
		pager.setTotalCount(financialAssetMapper.countByExample(example));

		return pager;
	}

	@Override
	public FinancialAsset addFinancialAsset(FinancialAsset financialAsset) {

		financialAsset.setCreateDate(new Date());
		financialAsset.setModifyDate(new Date());
		financialAsset.setInventory(BigDecimal.ZERO);
		this.financialAssetMapper.insert(financialAsset);
		addFinancialAssetInStock(financialAsset);

		return financialAsset;
	}

	/**
	 * 添加金融资产入库
	 *
	 * @param financialAsset
	 */
	private void addFinancialAssetInStock(FinancialAsset financialAsset) {

		FinancialAssetStockEntry entry = new FinancialAssetStockEntry();
		entry.setFinancialAsset(financialAsset);
		entry.setPurpose(FinancialAssetStockEntry.Purpose.NewFinancialAsset);
		entry.setPostingDate(new Date());
		entry.setAmount(financialAsset.getAmount());

		inStock(entry);

	}

	@Override
	public FinancialAsset findFinancialAssetById(Long id) {
		return this.financialAssetMapper.selectByPrimaryKey(id);
	}

	@Override
	public FinancialAsset updateFinancialAsset(FinancialAsset financialAsset) {

		FinancialAsset f = this.financialAssetMapper
				.selectByPrimaryKey(financialAsset.getId());

		// 不能修改资产金额、起息日、到期日，避免影响库存管理

		f.setName(financialAsset.getName());
		f.setPublisher(financialAsset.getPublisher());
		f.setProductForm(financialAsset.getProductForm());
		f.setUnderlyingAsset(financialAsset.getUnderlyingAsset());
		f.setManagementUnit(financialAsset.getManagementUnit());
		f.setFormingRoute(financialAsset.getFormingRoute());
		f.setLegalOpinion(financialAsset.getLegalOpinion());
		f.setAdviceProvider(financialAsset.getAdviceProvider());
		f.setValuation(financialAsset.getValuation());
		f.setAssetCoverage(financialAsset.getAssetCoverage());
		f.setValuationAgency(financialAsset.getValuationAgency());
		f.setCashFlowAssessment(financialAsset.getCashFlowAssessment());
		f.setCashFlowCoverage(financialAsset.getCashFlowCoverage());
		f.setCashFlowAssessmentResult(financialAsset
				.getCashFlowAssessmentResult());
		f.setCashFlowAssessmentAgency(financialAsset
				.getCashFlowAssessmentAgency());
		f.setMeasureToIncreaseTrust(financialAsset.getMeasureToIncreaseTrust());
		f.setIncreaseTrustAgency(financialAsset.getIncreaseTrustAgency());
		f.setRiskRating(financialAsset.getRiskRating());
		f.setRiskAssessmentAgency(financialAsset.getRiskAssessmentAgency());
		f.setRemark(financialAsset.getRemark());
        f.setProtocolIds(financialAsset.getProtocolIds());
        if(financialAsset.getDisable() == null){
        	f.setDisable(false);
        }else{
        	f.setDisable(financialAsset.getDisable());
        }
		this.financialAssetMapper.updateByPrimaryKey(f);

		return f;
	}

	@Override
	public void deleteFinancialAssetById(Long id) throws Exception {

		// 已经发售产品，不能删除资产
		if (isSoldProduct(id)) {
			throw new Exception("已经发售产品，不能删除资产");
		}

		FinancialAsset financialAsset = this.financialAssetMapper
				.selectByPrimaryKey(id);
		this.financialAssetMapper.deleteByPrimaryKey(financialAsset);

		// 删除库存记录
		this.financialAssetStockEntryMapper.deleteByFinancialAssetId(id);
	}

	private boolean isSoldProduct(Long financialAssetId) {
		ProductExample example = new ProductExample();
		example.appendCriterion("financialAsset_id=", financialAssetId);
		int count = productMapper.countByExample(example);
		return count > 0;
	}

	@Override
	public List<FinancialAsset> findFinancialAssetInventory() {

		FinancialAssetExample example = new FinancialAssetExample();

		Date now = new Date();
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		example.appendCriterion("disable = 0");
		example.appendCriterion("inventory > 0");
		example.appendCriterion("dueDate >=", format.format(now));
		example.setOrderByClause("inventory desc");

		Pager<FinancialAsset> pager = new Pager<>();
		pager.setPageSize(10000);
		return this.financialAssetMapper.selectByExample(example, pager);
	}

	@Override
	public List<ProductSettlementDate> findProductSettlementDatesByFinancialAssetId(
			Long financialAssetId) {

		return this.financialAssetMapper
				.findProductSettlementDatesByFinancialAssetId(financialAssetId);
	}

	@Override
	public List<ProductSettlementDate> findProductSettlementDatesByProductId(
			Long productId) {

		return this.financialAssetMapper
				.findProductSettlementDatesByProductId(productId);
	}

	@Override
	public List<FinancialAssetStockEntry> findStockEntriesByFinancialAssetId(
			Long id) {

		FinancialAssetStockEntryExample example = new FinancialAssetStockEntryExample();
		example.appendCriterion("financialAsset_id =", id);
		example.setOrderByClause("postingDate desc");

		Pager<FinancialAssetStockEntry> pager = new Pager<>();
		pager.setPageSize(10000);
		return this.financialAssetStockEntryMapper.selectByExample(example,
				pager);
	}

	@Override
	public List<FinancialAssetStockEntry> findEntriesByFinancialAssetId(
			Long financialAssetId) {

		FinancialAssetStockEntryExample example = new FinancialAssetStockEntryExample();
		example.appendCriterion("financialAsset_id =", financialAssetId);

		Pager<FinancialAssetStockEntry> pager = new Pager<>();
		pager.setPageSize(10000);

		return this.financialAssetStockEntryMapper.selectByExample(example,
				pager);
	}

	@Override
	public void inStock(FinancialAssetStockEntry financialAssetStockEntry) {

		// 添加入库记录
		checkFinancialAssetStockEntry(financialAssetStockEntry);
		financialAssetStockEntry.setCreateDate(new Date());
		financialAssetStockEntry.setModifyDate(new Date());
		financialAssetStockEntry.setType(FinancialAssetStockEntry.Type.In);
		financialAssetStockEntryMapper.insert(financialAssetStockEntry);

		this.updateFinancialAssetStock(financialAssetStockEntry
				.getFinancialAsset().getId());
	}

	/**
	 * 检查出入库记录
	 * 
	 * @param financialAssetStockEntry
	 */
	private void checkFinancialAssetStockEntry(
			FinancialAssetStockEntry financialAssetStockEntry) {

		if (financialAssetStockEntry.getFinancialAsset() == null) {
			throw new IllegalArgumentException("金融资产为空");
		}
		if (financialAssetStockEntry.getPurpose() == null) {
			throw new IllegalArgumentException("用途为空");
		}
		if (financialAssetStockEntry.getPostingDate() == null) {
			throw new IllegalArgumentException("出入库时间为空");
		}
		if (financialAssetStockEntry.getAmount() == null) {
			throw new IllegalArgumentException("金额为空");
		}
	}

	@Override
	public void outStock(FinancialAssetStockEntry financialAssetStockEntry) {

		this.checkFinancialAssetStockEntry(financialAssetStockEntry);

		// 添加出库记录
		financialAssetStockEntry.setFinancialAsset(this.financialAssetMapper
				.selectByPrimaryKey(financialAssetStockEntry
						.getFinancialAsset().getId()));
		this.checkFinancialAssetOutStockEntry(financialAssetStockEntry);

		financialAssetStockEntry.setCreateDate(new Date());
		financialAssetStockEntry.setModifyDate(new Date());
		financialAssetStockEntry.setType(FinancialAssetStockEntry.Type.Out);
		this.financialAssetStockEntryMapper.insert(financialAssetStockEntry);

		this.updateFinancialAssetStock(financialAssetStockEntry
				.getFinancialAsset().getId());
	}

	/**
	 * 检查出库记录
	 * 
	 * @param financialAssetStockEntry
	 *            出库记录
	 */
	private void checkFinancialAssetOutStockEntry(
			FinancialAssetStockEntry financialAssetStockEntry) {

		Product product = financialAssetStockEntry.getProduct();
		FinancialAsset financialAsset = financialAssetStockEntry
				.getFinancialAsset();

		// 到期日
		Date dueDate = product.getDueDate();
		if (dueDate.after(financialAsset.getDueDate())) {
			throw new IllegalArgumentException("产品到期日大于金融资产到期日");
		}
	}

	@Override
	public void productSellCloseAdjustStock(Long productId) {

		Product product = this.productMapper.selectByPrimaryKey(productId);

		if (product == null) {
			return;
		}
		if(product.getFinancialAsset() == null){
			return;
		}

		// 是否销售结束
		if (!product.getTag().equals(4)) {
			this.updateFinancialAssetStock(product.getFinancialAsset().getId());
			return;
		}

		// 销售结束金额已出入库，则不处理
		if (existProductSoldOutStockEntry(productId)) {
			this.updateFinancialAssetStock(product.getFinancialAsset().getId());
			return;
		}

		if (product.getTotalAmount().compareTo(product.getSoldAmount()) == 1) {
			soldInStock(product);
		} else if (product.getTotalAmount().compareTo(product.getSoldAmount()) == -1) {
			oversellOutStock(product);
		}
	}

	/**
	 * 是否存在产品销售结束出入库记录
	 * 
	 * @param productId
	 *            产品ID
	 * @return true - 存在，false - 不存在
	 */
	private boolean existProductSoldOutStockEntry(Long productId) {

		FinancialAssetStockEntryExample example = new FinancialAssetStockEntryExample();
		example.appendCriterion("(purpose = 'SoldInStock' or purpose = 'Oversell')");
		example.appendCriterion("product_id =", productId);

		int count = this.financialAssetStockEntryMapper.countByExample(example);

		return count > 0;
	}

	/**
	 * 超卖出库
	 * 
	 * @param product
	 */
	private void oversellOutStock(Product product) {

		BigDecimal amount = product.getSoldAmount().subtract(
				product.getTotalAmount());
		FinancialAsset financialAsset = product.getFinancialAsset();
		FinancialAssetStockEntry entry = new FinancialAssetStockEntry();
		entry.setFinancialAsset(financialAsset);
		entry.setPurpose(FinancialAssetStockEntry.Purpose.Oversell);
		entry.setPostingDate(new Date());
		entry.setAmount(amount);
		entry.setProduct(product);

		this.outStock(entry);
	}

	/**
	 * 未售完金额入库
	 * 
	 * @param product
	 */
	private void soldInStock(Product product) {

		BigDecimal amount = product.getTotalAmount().subtract(
				product.getSoldAmount());
		FinancialAsset financialAsset = product.getFinancialAsset();
		FinancialAssetStockEntry entry = new FinancialAssetStockEntry();
		entry.setFinancialAsset(financialAsset);
		entry.setPurpose(FinancialAssetStockEntry.Purpose.SoldInStock);
		entry.setPostingDate(new Date());
		entry.setAmount(amount);
		entry.setProduct(product);

		this.inStock(entry);
	}

	@Override
	public void calculatePaymentCollectionInStock(Date date) {

		List<SettlementCount> settlementCounts = countSettlementAmount(date);
		for (SettlementCount settlementCount : settlementCounts) {
			try {
				paymentCollectionInStock(date, settlementCount);
			} catch (Exception e) {
				logger.error(String.format("回款入库失败 金融资产ID:%s 金额:%s",
						settlementCount.getFinancialAssetId(),
						settlementCount.getAmount()));
			}
		}
	}

	/**
	 * 回款入库
	 * 
	 * @param date
	 *            回款日期
	 * @param settlementCount
	 *            结息金额统计
	 */
	private void paymentCollectionInStock(Date date,
			SettlementCount settlementCount) {

		FinancialAsset financialAsset = this.financialAssetMapper
				.selectByPrimaryKey(settlementCount.getFinancialAssetId());
		Product product = this.productMapper.selectByPrimaryKey(settlementCount
				.getProductId());

		if (financialAsset == null) {
			throw new RuntimeException("金融资产不存在 金融资产ID:"
					+ settlementCount.getFinancialAssetId());
		}
		if (product == null) {
			throw new RuntimeException("产品不存在 产品ID:"
					+ settlementCount.getProductId());
		}

		// 判断是否已经回款入库，防止重复入库
		if (isPaymentCollectionInStock(settlementCount, date)) {
			return;
		}

		if (settlementCount.getAmount() == null
				|| settlementCount.getAmount().compareTo(BigDecimal.ZERO) == 0) {
			return;
		}

		FinancialAssetStockEntry entry = new FinancialAssetStockEntry();
		entry.setFinancialAsset(financialAsset);
		entry.setPurpose(FinancialAssetStockEntry.Purpose.PaymentCollection);
		entry.setPostingDate(date);
		entry.setAmount(settlementCount.getAmount());
		entry.setProduct(product);

		this.inStock(entry);
	}

	/**
	 * 统计结息日的结息金额
	 * 
	 * @param date
	 *            结息日
	 * @return 结息金额
	 */
	private List<SettlementCount> countSettlementAmount(Date date) {

		DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date startDate = DateTimeUtil.getDateDay(date);
		Date endDate = DateTimeUtil.getDateAndMaxTime(date);
		Map<String, Object> map = new HashMap<>();
		map.put("startDate", format.format(startDate));
		map.put("endDate", format.format(endDate));

		return this.financingMapper.countSettlementAmountByDate(map);
	}

	/**
	 * 是否已经回款入库
	 * 
	 * @param settlementCount
	 *            用户回款结算统计
	 * @param now
	 *            当前时间
	 * @return true - 已回款入库，false - 未回款入库
	 */
	private boolean isPaymentCollectionInStock(SettlementCount settlementCount,
			Date now) {

		FinancialAssetStockEntryExample example = new FinancialAssetStockEntryExample();

		example.appendCriterion("type = 'In'");
		example.appendCriterion("purpose = 'PaymentCollection'");
		example.appendCriterion("financialAsset_id =",
				settlementCount.getFinancialAssetId());
		example.appendCriterion("product_id =", settlementCount.getProductId());
		example.appendCriterion("postingDate >=", DateTimeUtil.getDateDay(now));
		example.appendCriterion("postingDate <=",
				DateTimeUtil.getDateAndMaxTime(now));

		int count = this.financialAssetStockEntryMapper.countByExample(example);

		return count > 0;
	}

	@Override
	public void addFinancialAssetStockEntry(
			FinancialAssetStockEntry financialAssetStockEntry) {

		if (financialAssetStockEntry.getPurpose().getType()
				.equals(FinancialAssetStockEntry.Type.In)) {
			this.inStock(financialAssetStockEntry);
		} else if (financialAssetStockEntry.getPurpose().getType()
				.equals(FinancialAssetStockEntry.Type.Out)) {
			this.outStock(financialAssetStockEntry);
		} else {
			throw new IllegalArgumentException("无效出入库记录");
		}
	}

	@Override
	public void deleteFinancialAssetStockEntryById(Long id) {

		FinancialAssetStockEntry entry = this.financialAssetStockEntryMapper
				.selectByPrimaryKey(id);
		if (entry == null) {
			throw new IllegalArgumentException("无效到出入库记录ID");
		}

		int count = this.financialAssetStockEntryMapper
				.deleteByPrimaryKey(entry);
		if (count < 1) {
			throw new RuntimeException("删除出入库记录失败");
		}
		this.updateFinancialAssetStock(entry.getFinancialAsset().getId());
	}

	@Override
	public BigDecimal calculateFinancialAssetStock(Long financialAssetId,
			Date date) {

		Map<String, Object> map = new HashMap<>();
		map.put("financialAssetId", financialAssetId);
		map.put("date", date);

		BigDecimal soldOutProductAmount = this.financialAssetMapper
				.calculateSoldOutProductAmount(map);
		BigDecimal onSellProductAmount = this.financialAssetMapper
				.calculateOnSellProductAmount(map);
		BigDecimal paymentCollectionAmount = this.financialAssetMapper
				.calculatePaymentCollectionAmount(map);

		FinancialAsset financialAsset = this.financialAssetMapper
				.selectByPrimaryKey(financialAssetId);
		BigDecimal amount = financialAsset.getAmount();
		if (soldOutProductAmount != null) {
			amount = amount.subtract(soldOutProductAmount);
		}
		if (onSellProductAmount != null) {
			amount = amount.subtract(onSellProductAmount);
		}
		if (paymentCollectionAmount != null) {
			amount = amount.add(paymentCollectionAmount);
		}

		return amount;
	}

	@Override
	public void updateFinancialAssetStock(Long financialAssetId) {

		// 实时计算
		FinancialAsset financialAsset = this.financialAssetMapper
				.selectByPrimaryKey(financialAssetId);
		BigDecimal inventory = this.calculateFinancialAssetStock(
				financialAssetId, new Date());
		financialAsset.setInventory(inventory);
		this.financialAssetMapper.updateByPrimaryKey(financialAsset);

		// 入库明细累加库存
		// FinancialAsset financialAsset =
		// this.financialAssetMapper.selectByPrimaryKey(financialAssetId);
		//
		// BigDecimal inAmount =
		// this.financialAssetStockEntryMapper.sumInStockByFinancialAssetId(financialAssetId);
		// BigDecimal outAmount =
		// this.financialAssetStockEntryMapper.sumOutStockByFinancialAssetId(financialAssetId);
		//
		// if(inAmount == null){
		// inAmount = BigDecimal.ZERO;
		// }
		// if(outAmount == null){
		// outAmount = BigDecimal.ZERO;
		// }
		//
		// financialAsset.setInventory(inAmount.subtract(outAmount));
		// this.financialAssetMapper.updateByPrimaryKey(financialAsset);
	}

	@Override
	public void recreateFinancialAssetStockEntry(Long financialAssetId) {

		this.financialAssetStockEntryMapper
				.deleteByFinancialAssetId(financialAssetId);
		FinancialAsset financialAsset = this.financialAssetMapper
				.selectByPrimaryKey(financialAssetId);

		// 新资产入库
		FinancialAssetStockEntry newFinancialAssetInStockEntry = new FinancialAssetStockEntry();
		newFinancialAssetInStockEntry.setFinancialAsset(financialAsset);
		newFinancialAssetInStockEntry.setPostingDate(financialAsset
				.getValueDate());
		newFinancialAssetInStockEntry.setAmount(financialAsset.getAmount());
		newFinancialAssetInStockEntry
				.setPurpose(FinancialAssetStockEntry.Purpose.NewFinancialAsset);
		this.inStock(newFinancialAssetInStockEntry);

		// 发售产品出库，未售入库，超卖出库
		for (Product product : financialAsset.getProducts()) {

			FinancialAssetStockEntry saleOutStockEntry = new FinancialAssetStockEntry();
			saleOutStockEntry.setFinancialAsset(financialAsset);
			saleOutStockEntry.setProduct(product);
			saleOutStockEntry.setPostingDate(product.getStartTime());
			saleOutStockEntry.setAmount(product.getTotalAmount());
			saleOutStockEntry.setPurpose(FinancialAssetStockEntry.Purpose.Sale);
			this.outStock(saleOutStockEntry);

			if (product.getTag().equals(3) || product.getTag().equals(4)) {
				// 销售结束
				FinancialAssetStockEntry entry = new FinancialAssetStockEntry();
				entry.setFinancialAsset(financialAsset);
				entry.setPostingDate(product.getEndTime());
				entry.setProduct(product);

				if (product.getTotalAmount().compareTo(product.getSoldAmount()) == 1) {
					entry.setPurpose(FinancialAssetStockEntry.Purpose.SoldInStock);
					BigDecimal amount = product.getTotalAmount().subtract(
							product.getSoldAmount());
					entry.setAmount(amount);
					this.inStock(entry);
				} else if (product.getTotalAmount().compareTo(
						product.getSoldAmount()) == -1) {
					entry.setPurpose(FinancialAssetStockEntry.Purpose.Oversell);
					BigDecimal amount = product.getSoldAmount().subtract(
							product.getTotalAmount());
					entry.setAmount(amount);
					this.outStock(entry);
				}
			}
		}

		// 回款入库
		Date now = new DateTime().toLocalDate().toDate();
		Map<String, Object> map = new HashMap<>();
		map.put("financialAssetId", financialAssetId);
		map.put("date", now);
		List<ProductSettlementDate> productSettlementDates = this.financialAssetMapper
				.countProductSettlementDatesByFinancialAssetId(map);
		for (ProductSettlementDate productSettlementDate : productSettlementDates) {

			Product product = this.productMapper
					.selectByPrimaryKey(productSettlementDate.getProductId());
			FinancialAssetStockEntry entry = new FinancialAssetStockEntry();
			entry.setFinancialAsset(financialAsset);
			entry.setProduct(product);
			entry.setPostingDate(productSettlementDate.getSettlementDate());
			entry.setAmount(productSettlementDate.getAmount());
			entry.setPurpose(FinancialAssetStockEntry.Purpose.PaymentCollection);
			this.inStock(entry);
		}

	}

	@Override
	public List<Interest> getInterestByExample(InterestExample example) {
		return interestMapper.selectByExample(example, null);
	}

	@Override
	public int getInterestCountByExample(InterestExample example) {
		return interestMapper.countByExample(example);
	}
	
	/**
	 * 保底收益
	 * @param financing
	 * @param interest
	 */
	public void createMinTermInterest(Financing financing, BigDecimal interest, BigDecimal totalInterest){
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("financing_id", financing.getId());// 计息日
		//BigDecimal totalAmount = new BigDecimal(interestMapper.findInterestSum(params));
			params = new HashMap<String, Object>();
			params.put("valueDate", new Date());// 计息日
			params.put("interest", interest);// 当日利息
			params.put("financing_id", financing.getId());
			params.put("income", totalInterest);
			params.put("calculated", 0);
			params.put("user_id", financing.getUser().getId());
			
			interestMapper.insertInterest(params);
		
		
		
		
	}

	/**
	 * 生成一个金融包的每日利息
	 */
	public void createDayInterest(Financing financing) {
		Date valueDate = financing.getValueDate();
		int term = financing.getTerm();
		BigDecimal income = new BigDecimal("0");// 累计收益
		for (int i = 0; i < term; i++) {
			// 计算第N天应该得到的利息
			BigDecimal interest = new BigDecimal(financing.getAmount()
					.doubleValue()
					* (financing.getInterestRate().doubleValue())
					* (i + 1) / 360).setScale(2, RoundingMode.UP);
			// Interest dayInterest = new Interest();
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("valueDate", addDays(valueDate, i));// 计息日
			params.put("interest", interest.subtract(income));// 当日利息
			params.put("financing_id", financing.getId());
			params.put("income", interest);
			params.put("calculated", 0);
			params.put("user_id", financing.getUser().getId());
			// dayInterest.setValueDate(addDays(valueDate, i));//计息日
			// dayInterest.setCreateDate();//创建日期
			// dayInterest.setInterest(interest.subtract(income));//当日利息
			// dayInterest.setIncome(interest);//累计利息
			// dayInterest.setFinancing(financing);//相关金融包
			// dayInterest.setCalculated(0);//利息是否计算过
			// this.interestMapper.insert(dayInterest);
			interestMapper.insertInterest(params);
			income = interest;
		}
	}

//	public boolean refreshInterest(Financing financing) {
//		if (financing != null && financing.getId() != null) {
//			// 先删除原来的日利息信息
//			InterestExample interestExample = new InterestExample();
//			interestExample.appendCriterion("financing_id", financing.getId());
//			interestMapper.deleteByExample(interestExample);
//			createDayInterest(financing);
//		}
//		return true;
//	}

	@Override
	@Transactional
	public boolean updateFinancing(Financing financing) {
		return financingMapper.updateByPrimaryKey(financing) > 0;
	}

	@Override
	public List<Financing> findFinancingByExample(FinancingExample example,
			Pager<Financing> pager) {
		if (example == null) {
			example = new FinancingExample();
		}
		if (pager == null) {
			return financingMapper.selectByExample(example, pager);
		} else {
			List<Financing> list = financingMapper.selectByExample(example,
					pager);
			int count = financingMapper.countByExample(example);
			pager.setList(list);
			pager.setTotalCount(count);
			return list;
		}
	}

	@Override
	public Financing findFinancingById(Long id) {
		return financingMapper.selectByPrimaryKey(id);
	}

	@Override
	@Transactional
	public boolean calculateInterest(Financing financing) {
		// List<Map<String, Object>> list =
		// financingMapper.findIncomeGroupByFinancing();
		// if(!isEmpty(list)){
		// for(Map<String,Object> item : list){
		// Integer financing_id = (Integer) item.get("financing_id");
		// BigDecimal income = (BigDecimal) item.get("income");
		// Financing financing2 =
		// financingMapper.selectByPrimaryKey(financing_id.longValue());
		// if(financing2!=null){
		// financing2.setIncome(income);
		// financing2.setModifyDate(getDate());
		// financingMapper.updateByPrimaryKey(financing2);
		// }
		// }
		// }
		BigDecimal income = financingMapper
				.findIncomeGroupByFinancing(financing.getId());
		if (income == null)
			income = new BigDecimal("0");

		return true;
		// if(financing!=null && financing.getId()!=null){
		// Date date = new Date();
		// if(!isCalculated(financing.getId(), ISO_DATE_FORMAT.format(date))){
		//
		// }
		// 取出今天的利息信息
		// InterestExample example = new InterestExample();
		// example.appendCriterion("financing_id=", financing.getId());

		// example.appendCriterion("valueDate=", new
		// java.sql.Date(addDays(date,-1).getTime()));
		// Interest nowInterest = interestMapper.selectOneByExample(example);
		// 取出用户的金融账户
		// if (nowInterest != null && nowInterest.getCalculated().intValue()==0)
		// {
		// Balance balance =
		// balanceMapper.selectByPrimaryKey(financing.getUser().getId());
		// balance.setIncome(balance.getIncome()==null?nowInterest.getInterest():balance.getIncome().add(nowInterest.getInterest()));
		// balance.setAsset(balance.getAsset()==null?nowInterest.getInterest():balance.getAsset().add(nowInterest.getInterest()));
		// balance.setModifyDate(date);
		// balanceMapper.updateByPrimaryKey(balance);
		//
		// nowInterest.setCalculated(1);
		// nowInterest.setModifyDate(RateUtil.getDate());
		// interestMapper.updateByPrimaryKey(nowInterest);
		// }
		// financingMapper.updateByPrimaryKey(financing);
		// }
		// return false;
	}

	/**
	 * 判断某个金融包在某一天是否算过了利息
	 * 
	 * @return
	 */
	private boolean isCalculated(Long id, String date) {
		return redisTemplate.opsForValue().get("VALUE_DATE_" + id + "_" + date) != null;
	}
	
	public Long calculate(Financing financing) {
		logger.info("========================>正在处理id[" + financing.getId() + "]的记录");
		int term = financing.getRemains() < financing.getTerm() ? financing.getRemains() : financing.getTerm();
		
		Set<String> dates = new HashSet<String>();
		for(int k=0;k<term;k++){
			Date d = addDays(financing.getValueDate(), k);
			logger.info("========================>正在处理id[" + financing.getId() + "]，日期[" + formatDate(d) + "]");
			dates.add(formatDate(d));
		}
		Map<String,Object> params = new LinkedCaseInsensitiveMap<Object>(2);
		params.put("financing_id", financing.getId());
		params.put("dates", dates);
		
		List<Map<String,Object>> interests = interestMapper.findWholeInterestList(params);
		int index = 0;
		BigDecimal income = new BigDecimal("0");// 累计收益
		for(Map<String,Object> inte:interests){
			if (inte.get("interest") == null
					|| inte.get("income") == null) {
				BigDecimal rate = new BigDecimal(0);
				switch (financing.getProduct().getCategory()) {
				case CURRENT:
					String dateStr = formatDate(getMinDate(addDays(financing.getValueDate(), index), financing.getExpiredDate()));
					for(FinancingIncomeRule rule:financing.getFinancingIncomeRules()){
						if (dateStr.compareTo(rule.getDueDate()) <= 0) {
							rate = rule.getInterestRate();
							break;
						}
					}
					break;
				default:
					rate = financing.getInterestRate();
					break;
				}
				
				BigDecimal interest = new BigDecimal(financing.getAmount()
						.doubleValue()
						* (rate.doubleValue())
						* (index + 1) / 360).setScale(2, RoundingMode.UP);
				
				params.clear();
				params.put("valueDate", addDays(financing.getValueDate(), index));// 计息日
				params.put("interest", interest.subtract(income));// 当日利息
				params.put("financing_id", financing.getId());
				params.put("income", interest);
				params.put("calculated", 0);
				params.put("user_id", financing.getUser().getId());
				logger.info(String.valueOf(params));
				interestMapper.insertInterest(params);
				income = interest;
			} else {
				income = (BigDecimal) inte.get("income");
			}
			index++;
		}
		return financing.getId();
	}

	// @Transactional
	@Override
	public void calculate(AsyncTaskExecutor executor) {
		logger.info("=========================>计算利息开始");
		final Date date = getInstance().getTime();
		final String now = formatDate(date);
		final Map<String, Object> params = new LinkedCaseInsensitiveMap<Object>();
		// 执行开始计息的语句
		logger.info("=========================>执行开始计息的语句");
		params.put("status", Financing.Status.STATUS_INTEREST.toString());
		params.put("date", now);
		financingMapper.startCalculateInterest(params);
		// 执行结束计息的语句
		logger.info("=========================>执行结束计息的语句");
		params.put("status", Financing.Status.STATUS_EXPIRED.toString());
		params.put("date", now);
		financingMapper.finishCalculateInterest(params);
		//计算每天的利息
		Map<String, Object> financingParams = new HashMap<String, Object>();
		financingParams.put("date", new java.sql.Timestamp(date.getTime()));
		List<Financing> list = financingMapper.findFinancingForCalculateByProperty(financingParams, null);
		for(Financing financing : list){
			calculate(financing);
		}
		params.clear();
		params.put("date",formatDate(addDays(date, -1)));
		financingMapper.updateFinancingIncomeById(params);
		logger.info("=========================>计算利息结束");
	}

	@Override
	public List<Financing> findFinancingByValueDate(String valueDate) {
		FinancingExample example = new FinancingExample();
		example.appendCriterion("str_to_date(valueDate,'%Y-%m-%d')=", valueDate);
		Pager<Financing> pager = new Pager<>();
		pager.setPageSize(Integer.MAX_VALUE);
		return financingMapper.selectByExample(example, pager);
	}

	@Override
	public List<Financing> findFinancingByCreateDate(String createDate) {
		FinancingExample example = new FinancingExample();
		example.appendCriterion("str_to_date(createDate,'%Y-%m-%d')=",
				createDate);
		Pager<Financing> pager = new Pager<>();
		pager.setPageSize(Integer.MAX_VALUE);
		return financingMapper.selectByExample(example, pager);
	}

	@Override
	public List<Financing> findFinancingTop10ByProductId(Long product_id) {
		return financingMapper.findFinancingTop10ByProductId(product_id);
	}

	@Override
	public Pager<Financing> findUnrepaidFinancing(Long bankCardId) {
		Pager<Financing> pager = new Pager<Financing>();
		int count = financingMapper.countUnrepaidFinancing(bankCardId);
		pager.setPageCount(count);
		if (count > 0) {
			List<Financing> list = financingMapper
					.findUnrepaidFinancing(bankCardId);
			pager.setList(list);
		}
		return pager;
	}

	@Override
	public BigDecimal findTotalAmountForMarchTraffic2015(
			Map<String, Object> params) {
		return financingMapper.findTotalAmountForMarchTraffic2015(params);
	}
	
	@Override
	public boolean findActivityIntervelAmounts(Map<String, Object> params) {
		BigDecimal total = financingMapper.findActivityIntervelAmounts(params);
		
		if (total == null) 
			return false;
		else if (total.compareTo((BigDecimal)params.get("amount")) == -1)
			return false;
		else 
			return true;
	}
	
	@Override
	public boolean findSingleAmount(Map<String, Object> params) {
        int count = financingMapper.findSingleAmount(params);
		
		if (count == 0) 
			return false;
		else 
			return true;
	}
	
	@Override
	public boolean findSingleAmountBy51(Map<String, Object> params) {
		int count = financingMapper.findSingleAmountBy51(params);
		
		if (count == 0) 
			return false;
		else 
			return true;
	}
	
	@Override
	public Financing findLatestFinancingByUser(User user) {
		FinancingExample example = new FinancingExample();
		example.appendCriterion("user_id=", user.getId());
		example.setOrderByClause("id DESC");
		return this.financingMapper.selectOneByExample(example);
	}

	@Override
	@Transactional(timeout=15)
	public Integer saveRedemptionRequest(Financing financing) {
		synchronized (CommonServiceImpl.lock) {
			//先验证是否可赎回
			RedemptionRequestExample example = new RedemptionRequestExample();
			example.appendCriterion("financing_id=", financing.getId());
			if(redemptionRequestMapper.countByExample(example)==0){
				RedemptionRequest redemptionRequest = new RedemptionRequest();
				redemptionRequest.setCreateDate(getInstance().getTime());
				redemptionRequest.setModifyDate(redemptionRequest.getCreateDate());
				redemptionRequest.setFinancing(financing);
//				redemptionRequestMapper.insert(redemptionRequest);
				
				FinancingIncomeRule rule = financing.getFinancingIncomeRule();
				if(rule!=null){
					financing.setTerm(rule.getHoldingTime());
					financing.setSettlementDate(addDays(financing.getValueDate(), rule.getHoldingTime()));
					financing.setInterestRate(rule.getInterestRate());
					this.financingMapper.updateByPrimaryKey(financing);
				}
				return redemptionRequestMapper.insert(redemptionRequest);
			}
			return 0;
		}
	}

	@Override
	public void addFinancingIncomeRules(Long id) {
		Financing financing = this.financingMapper.selectByPrimaryKey(id);
		if(financing!=null){
			switch (financing.getProduct().getCategory()) {
			case CURRENT:
				financingIncomeRuleMapper.deleteFinancingIncomeRulesByFinancing(id);
				if(!isEmpty(financing.getProduct().getEarningsRules())){
					for(int i=0;i<financing.getProduct().getEarningsRules().size();i++){
						ProductEarningsRule rule = financing.getProduct().getEarningsRules().get(i);
						
						FinancingIncomeRule incomeRule = new FinancingIncomeRule();
						incomeRule.setCreateDate(financing.getOrder().getCreateDate());
						incomeRule.setModifyDate(financing.getOrder().getCreateDate());
						incomeRule.setFinancing(financing);
						incomeRule.setHoldingTime(rule.getHoldingTime());
						incomeRule.setInterestRate(rule.getFinalInterestRate());
						incomeRule.setDueDate(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1)));
						incomeRule.setRedemptionStartTime(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1-4-7)));
						incomeRule.setRedemptionEndTime(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1-4)));
						incomeRule.setStage(i+1);
						incomeRule.setLast(i == financing.getProduct().getEarningsRules().size()-1);
						financingIncomeRuleMapper.insert(incomeRule);
					}
				}
				break;
			default:
				break;
			}
		}
	}

	@Override
	public BigDecimal findTotalAmountByProperty(Map<String, Object> params) {
		return financingMapper.findTotalAmountByProperty(params);
	}

	@Override
	public List<Financing> findFinancingRankByProperty(
			Map<String, Object> params) {
		return financingMapper.findFinancingRankByProperty(params);
	}

	@Override
	public List<Financing> findUserFinancingRankByProperty(
			Map<String, Object> params) {
		return financingMapper.findUserFinancingRankByProperty(params);
	}

	@Override
	public void findApplyFinancingByKeywordAndDate(Pager<Financing> pager, String keyword, Date settlementDate) {
        
		if (keyword == null) {
			keyword = "";
		}
		keyword = "%" + keyword + "%";
		
        pager.setList(this.financingMapper.findApplyFinancingByKeywordAndDate(
        		pager.getStartNumber(),
        		pager.getEndNumber(),
        		keyword, settlementDate));
        pager.setTotalCount(this.financingMapper.countApplyFinancingByKeywordAndDate(keyword, settlementDate));
	}

	@Override
	public boolean hasBondQualification(User user) {
		boolean qualification = false;
		if(user!=null){
			JSONObject config = new JSONObject(configureService.getActivityConfig("HEJIA_BOND_CONFIG")).getJSONObject("config");
			JSONArray array = config.getJSONArray("white_list");
			qualification = array.contains(user.getMobile());
			if(!qualification){
				qualification = checkUserQualification(user, config);
			}
			//如果没资格，再判断是否是有资格的用户邀请过来的
			if(!qualification){
				InvitationExample example = new InvitationExample();
				example.appendCriterion("invitee_id=", user.getId());
				Invitation invitation = this.invitationMapper.selectOneByExample(example);
				if(invitation!=null){
					User inviter = invitation.getInviter();
					
					qualification = checkUserQualification(inviter, config);
				}
			}
		}
		return qualification;
	}

	private boolean checkUserQualification(User user, JSONObject config){
		if(user!=null){
			FinancingExample example = new FinancingExample();
			example.appendCriterion("date(settlementDate)>=", config.getString("date2"));
			example.appendCriterion("date(settlementDate)<=", config.getString("date1"));
			example.appendCriterion("user_id=", user.getId());
			int count = this.financingMapper.countByExample(example);
			if(count > 0){
				return false;
			}
			BigDecimal standard = new BigDecimal(config.getIntValue("amount"));
			
			Map<String, Object> params = new LinkedHashMap<String, Object>();
			params.put("user_id", user.getId());
			BigDecimal total = this.financingMapper.findTotalAmountByProperty(params);
			if(total == null || total.compareTo(standard)<0){
				return false;
			}
			return true;
		}
		return false;
	}

	@Override
	public int checkClassify(User user) {
		Assert.notNull(user);
		String now = formatDate(Calendar.getInstance());
		int classify = 1;
		int count = 0;
		//累计购买金额 余额
		BigDecimal total = new BigDecimal(0), balance = new BigDecimal(0);
		FinancingExample example = new FinancingExample();
		example.appendColumnName("createDate,settlementDate,amount");
		example.appendCriterion("`user_id`=", user.getId());
		example.setOrderByClause("settlementDate DESC");
		List<Financing> list = this.financingMapper.selectByExample(example, null);
		count = list.size();
		for(Financing item:list){
			//计算累计
			total = total.add(item.getAmount());
			//计算余额
			if(formatDate(item.getSettlementDate()).compareTo(now)>0){
				balance = balance.add(item.getAmount());
			}
		}
		//尝试交易用户(trying)
		if(count<=2 && total.compareTo(new BigDecimal(1500))<0){
			classify = 0;
		} else if(balance.compareTo(new BigDecimal(0))<=0){
			Financing lastFinancing = list.get(0);
			long stopDays = calculateDate(lastFinancing.getSettlementDate(), addDays(new Date(), -1));
			if(stopDays>80){
				classify = 0;
			}
		} else {
			total = new BigDecimal(0);
			for(Financing item:list){
				int interval = calculateDate(item.getCreateDate(), new Date());
				logger.info(interval);
				if(interval<=30){
					total = total.add(item.getAmount());
				}
			}
			if(total.compareTo(new BigDecimal(35000))>=0){
				classify = 2;
			}
		}
		return classify;
	}

	@Override
	public BigDecimal getTatalIncomeForUer() {
		return financingMapper.getTatalIncomeForUer();
	}
	
	//单日利息
	@Override
	public BigDecimal calculateInterest(Financing financing, int days){
		BigDecimal interest = new BigDecimal(financing.getAmount()
				.doubleValue()
				* (financing.getInterestRate().doubleValue())
				 * days / 360).setScale(2, RoundingMode.UP);
		return interest;
	}
}
